package main

import (
	"log"

	"flag"
	"fmt"
	"os"
	"strconv"
	"strings"

	"code.google.com/p/rsc/keychain"

	"code.google.com/p/goplan9/plan9/acme"
	"code.google.com/p/marius/campfire"
)

var cf *campfire.Campfire

func usage() {
	fmt.Fprintf(os.Stderr, "usage: Cf realm [roomid]\n")
	os.Exit(1)
}

func main() {
	// todo: support "present" as a magic ID.

	defer acme.DeleteAll()
	flag.Parse()

	if flag.NArg() < 1 {
		usage()
	}

	realm := flag.Args()[0]
	_, token, err := keychain.UserPasswd(fmt.Sprintf("%s.campfirenow.com", realm), "")
	if err != nil {
		log.Fatal(err)
	}

	cf, err = campfire.New(token, realm)
	if err != nil {
		log.Fatal(err)
	}

	switch flag.NArg() {
	case 0:
		usage()
	case 1:
		lobby()
	default:
		for _, arg := range flag.Args()[1:] {
			id, err := strconv.Atoi(arg)
			if err != nil {
				log.Fatalf("\"%s\" not a valid room id", arg)
			}
			chat(id)
		}
	}
}

func chat(roomId int) {
	room, err := cf.GetRoom(roomId)
	if err != nil {
		log.Print(err)
		return
	}
	w, err := acme.New()
	if err != nil {
		log.Print(err)
		return
	}
	defer w.Ctl("delete")
	w.Name("/campfire/%d", room.Id)
	w.Ctl("cleartag")
	w.Printf("tag", " Who | <%s> %s", room.Name, room.Topic)

	w.Printf("body", "\n")
	w.Addr("#0")
	w.Ctl("clean")

	live, err := room.MonitorFull()
	if err != nil {
		log.Print(err)
		return
	}
	events := w.EventChan()
	transcript := room.Transcript()

	msgs := transcript

	aux := make(chan []string)

	// todo: hold/unhold for text
	for {
		select {
		case e := <-events:
			switch e.C2 {
			case 'x', 'X':
				switch string(e.Text) {
				case "Del":
					goto Done
				case "Who":
					go func() {
						room, err := cf.GetRoom(roomId)
						if err != nil {
							aux <- []string{fmt.Sprintf("<error> %s", err)}
							return
						}
						lines := make([]string, len(room.Users))
						for i, u := range room.Users {
							if u.Name != nil && u.Email != nil {
								lines[i] = fmt.Sprintf("<who> %s - %s", *u.Name, *u.Email)
							} else {
								lines[i] = fmt.Sprintf("<who> %v", u)
							}
						}
						aux <- lines
					}()
				default:
					w.WriteEvent(e)
				}
			}

			saveq0, saveq1, err := w.ReadAddr()
			if err != nil {
				log.Fatal(err)
			}
			// log.Printf("%+v", e)

			err = w.Addr("#%d+1,$", saveq1)
			if err == nil {
				data, err := w.ReadAll("xdata")
				if err != nil {
					log.Fatal(err)
				}
				input := string(data)
				if strings.Contains(input, "\n") {
					err = w.Addr("#%d+1,$", saveq1)
					if err != nil {
						log.Fatal(err)
					}
					err = w.Printf("data", "")
					if err != nil {
						log.Fatal(err)
					}
					input = strings.TrimSpace(input)
					go func() {
						err := room.Speak(input)
						//log.Printf("speak <%s>", input)
						if err != nil {
							log.Print(err)
						}
					}()
				}
			}
			w.Addr("#%d,#%d", saveq0, saveq1)
			w.Ctl("clean")
		case lines := <-aux:
			for _, line := range lines {
				w.Printf("data", "%s\n", line)
			}
		case m, ok := <-msgs:
			if !ok {
				if msgs == transcript {
					msgs = live
					continue
				} else {
					log.Fatal("message channel closed")
				}
			}

			uname := "???"
			if m.User != nil {
				uname = *m.User.Name
			}

			switch *m.Type {
			case "TextMessage":
				w.Printf("data", "<%s> %s\n", uname, *m.Body)
				w.Ctl("clean")
				w.Ctl("show")
			case "PasteMessage":
				lines := strings.Split(*m.Body, "\n")
				w.Printf("data", "<%s>\n", uname)
				for _, line := range lines {
					w.Printf("data", "	%s\n", line)
				}

			default:
			}

		}
	}
Done:
}

func lobby() {
	rooms, err := cf.GetRooms()
	if err != nil {
		log.Fatal(err)
	}

	for _, r := range rooms {
		fmt.Printf("Cf %s %d	# %s: %s\n", r.Realm, r.Id, r.Name, r.Topic)
	}

	os.Exit(0)
}
